package gee

import (
	"log"
	"net/http"
)

// HandlerFunc defines(定义) the request handler used by gee
type HandlerFunc func(*Context)

// Engine implement(实现) the interface of ServeHTTP
type (
	RouterGroup struct {
		prefix      string        //前缀，比如 /，或者 /api
		middlewares []HandlerFunc //support middleware（支持中间件），应用在该分组上的中间件
		parent      *RouterGroup  //support nesting（支持嵌套），当前分组的父亲
		engine      *Engine       //all groups share a Engine instance(所有组共享一个Engine实例)
		//整个框架的资源都是由 Engine 统一协调的，那么还可以通过Engine 间接地访问各种接口
	}
	Engine struct {
		*RouterGroup
		router *router
		groups []*RouterGroup //store all grouper
	}
)

// New is the constructor(构造器) of gee.Engine
func New() *Engine {
	engine := &Engine{router: newRouter()}
	engine.RouterGroup = &RouterGroup{engine: engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
}

// Group is defined to create a new RouterGroup
// remember all groups share the same Engine instance
func (group *RouterGroup) Group(prefix string) *RouterGroup {
	engine := group.engine
	newGroup := &RouterGroup{
		prefix: group.prefix + prefix,
		parent: group,
		engine: engine,
	}
	engine.groups = append(engine.groups, newGroup)
	return newGroup
}

func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) {
	pattern := group.prefix + comp
	log.Printf("Route %4s - %s", method, pattern)
	group.engine.router.addRoute(method, pattern, handler)
}

// GET defines the method to add GET request
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
	group.addRoute("GET", pattern, handler)
}

// POST defines the method to add POST request
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
	group.addRoute("POST", pattern, handler)
}

// Run defines the method to start a http server
func (engine *Engine) Run(addr string) (err error) {
	return http.ListenAndServe(addr, engine) //engine 是实现了 http.Handler 接口的结构体实例
}

// ServeHTTP 用来实现 http.Handler 接口
func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := newContext(w, r)
	engine.router.handler(c)
}
